/**
* Original Author of this file: Martin Mouritzen. (martin@nano.dk)
*
*
* (Lack of) Documentation:
*
*
* If a finishedLoading method exists, it will be called when the tree is loaded.
* (good to display a div, etc.).
*
*
* You have to set the variable rootNode (as a TreeNode).
*
* You have to set a container element, this is the element in which the tree will be.
*
*
* TODO:
* Save cookies better (only 1 cookie for each tree). Else the page will totally cookieclutter.
*
***********************************************************************
* Configuration variables.
************************************************************************/

// Should the rootNode be displayed.
var showRootNode = true;

// Should the dashed lines between nodes be shown.
var showLines = true;

// Should the nodes be sorted? (You can either specify a number, then it will be sorted by that, else it will
// be sorted alphabetically (by name).
var sortNodes = false;

// This is IMPORTANT... use an unique id for each document you use the tree in. (else they'll get mixed up).
var documentID = window.location.href;

// being read from cookie.
var nodesOpen = new Array();

// RootNode of the tree.
var rootNode;

// Container to display the Tree in.
var container;

// Shows/Hides subnodes on startup
var showAllNodesOnStartup = false;

// Is the roots dragable?
var dragable = false;

// Use cookies. Added by AE
var useCookieState = true;

// Relative Path to icons used by the control (such as line.gif, plus.gif etc). Added by AE.
var iconPath = 'images';

// support double click on a leaf  - added by AEI
var supportDoubleClick = false;

// Enable or disable keyboard events - added by AEI
var supportKeyboardNavigation = true;

/************************************************************************
* The following is just instancevariables.
************************************************************************/
var href = '';

// rootNodeCallBack name (if null, it's not selectable).
var rootNodeCallBack = null;

// selectedNode
var selectedNode = null;

var states = '';
var statearray = new Array();

var treeNodeEdited = null;

var editaborted = false;

var floatDragElement = null;
var colouredElement = null;
var draggedNodeID = null;
var lastDraggedOnNodeID = null;


/**
* The TreeNode Object
* @param id unique id of this treenode
* @param name The title of this node
* @param icon The icon if this node (Can also be an array with 2 elements, the first one will represent the closed state, and the next one the open state)
* @param param A parameter, this can be pretty much anything. (eg. an array with information).
* @param orderNumber an orderNumber If one is given the nodes will be sorted by this (else they'll be sorted alphabetically (If sorting is on).
*/
function TreeNode(id,name,icon,param,orderNumber) {
   this.id = id;
   this.childs = new Array();
   this.name = (name == null ? 'unset name' : name);
   this.icon = (icon == null ? '' : icon);
   this.parent = null;
   this.handler = null;
   this.param = (param == null ? '' : param);
   this.orderNumber = (orderNumber == null ? -1 : orderNumber);

   this.openeventlisteners = new Array();
   this.editeventlisteners = new Array();
   this.moveeventlisteners = new Array();
   this.haschilds = false;
   this.editable = false;
   this.linestring = '';

   this.nextSibling = null;
   this.prevSibling = null;

   this.childsHasBeenFetched = false;
   // Added by AEI - 'shown' flag is used to build the html on a lazy basis.
   this.shown = false;

   this.getID = function() {
      return this.id;
   }
   this.setName = function(newname) {
      this.name = newname;
   }
   this.getName = function() {
      return this.name;
   }
   this.getParam = function() {
      return this.param;
   }
   this.setIcon = function(icon) {
      this.icon = icon;
   }
   this.getIcon = function() {
      if (typeof(this.icon) == 'object') {
         return this.icon[0];
      }
      return this.icon;
   }
   this.getOpenIcon = function() {
      if (typeof(this.icon) == 'object') {
         return this.icon[1];
      }
      return this.icon;
   }
   this.hasIcon = function () {
      return this.icon != '';
   }
   this.getOrderNumber = function() {
      return this.orderNumber;
   }
   this.addOpenEventListener = function(event) {
      this.openeventlisteners[this.openeventlisteners.length] = event;
   }
   this.gotOpenEventListeners = function() {
      return (this.openeventlisteners.length > 0);
   }
   this.addEditEventListener = function(event) {
      this.editeventlisteners[this.editeventlisteners.length] = event;
   }
   this.gotEditEventListeners = function() {
      return (this.editeventlisteners.length > 0);
   }
   this.addMoveEventListener = function(event) {
      this.moveeventlisteners[this.moveeventlisteners.length] = event;
   }
   this.gotMoveEventListeners = function() {
      return (this.moveeventlisteners.length > 0);
   }
   this.addChild = function(childNode) {
      var possiblePrevNode = this.childs[this.childs.length - 1]
      if (possiblePrevNode) {
         possiblePrevNode.nextSibling = childNode;
         childNode.prevSibling = possiblePrevNode;
         // alert(childNode.prevSibling);
      }

      this.childs[this.childs.length] = childNode;
      childNode.setParent(this);

      if (sortNodes) {
         function sortByOrder(a,b) {
            var order1 = a.getOrderNumber();
            var order2 = b.getOrderNumber();
            if (order1 == -1 || order2 == -1) {
               return a.getName().toLowerCase() > b.getName().toLowerCase() ? 1 : -1;
            }
            else {
               if (order1 == order2) {
                  // If they got the same order number, then we'll sort by their title.
                  return a.getName().toLowerCase() > b.getName().toLowerCase() ? 1 : -1;
               }
               else {
                  return order1 - order2;
               }
            }
         }
         this.childs.sort(sortByOrder);
      }
   }
   this.removeChild = function(childNode) {
      var found = false;
      for (var i=0;i<this.childs.length;i++) {
         if (found) {
            this.childs[i] = this.childs[i + 1];
         }
         if (this.childs[i] == childNode) {
            if (i == (this.childs.length - 1)) {
               this.childs[i] = null;
            }
            else {
               this.childs[i] = this.childs[i + 1];
            }
            found = true;
         }
      }
      if (found) {
         this.childs.length = this.childs.length-1;
      }
   }
   this.resetChilds = function() {
      this.childs = new Array();
   }
   this.setHasChilds = function(hasChilds) {
      this.haschilds = hasChilds;
   }
   this.hasChilds = function() {
      if (this.haschilds == true) {
         return true;
      }
      return (this.childs.length > 0);
   }
   this.getChildCount = function() {
      return this.childs.length;
   }
   this.getFirstChild = function() {
      if (this.hasChilds()) {
         return this.childs[0];
      }
      return null;
   }
   this.gotHandler = function() {
      return this.handler != null;
   }
   this.setHandler = function(handler) {
      this.handler = handler;
   }
   this.getHandler = function() {
      return this.handler;
   }
   this.setParent = function(parent) {
      this.parent = parent;
   }
   this.getParent = function() {
      return this.parent;
   }
   this.getLineString = function() {
      return this.linestring;
   }
   this.setLineString = function(string) {
      this.linestring = string;
   }
   this.isEditable = function() {
      return this.editable;
   }
   this.setEditable = function(editable) {
      this.editable = editable;
   }
   this.isShown = function() {
      return this.shown;
   }
   this.setShown = function(shown) {
      this.shown = shown;
   }

}

// Added by AEI
function log(s)
{
   d = document.getElementById('debuginfo');
   if (d) {
      d.innerHTML  = "" + s;
      //d.innerHTML  = d.innerHTML  + "<br/>" + s;
   }
}
// Added by AEI
function logNode(treeNode)
{
   if (treeNode)
   {
      var s= "Node id=" + treeNode.getID() + "; open=" + isNodeExpanded(treeNode.getID()) + "; shwn=" + treeNode.isShown() + "; name=" + treeNode.getName();
      if (treeNode.hasChilds())
      {
         s = s + "; children=" + treeNode.getChildCount();
      }
      log(s);
   }
}

function getTreeNode(nodeID) {
   return findNodeWithID(rootNode,nodeID);
}

function findNodeWithID(node,nodeID) {
   if (node.getID() == nodeID) {
      return node;
   }
   else {
      if (node.hasChilds()) {
         for(var i=0;i<node.getChildCount();i++) {
            var value = findNodeWithID(node.childs[i],nodeID);
            if (value != false) {
               return value;
            }
         }
      }
      return false;
   }
}

//
// Added by AEI.
// Find the first node which has the given parameter (data)
//
function findNodeWithParam(node,param) {
   if (node.getParam() == param) {
      return node;
   }
   else {
      if (node.hasChilds()) {
         for(var i=0;i<node.getChildCount();i++) {
            var value = findNodeWithParam(node.childs[i],param);
            if (value != false) {
               return value;
            }
         }
      }
      return false;
   }
}

//
// Added by AEI
// Select given node and expand its parents if the selected node is already hidden.
//
function expandAndSelectNode(node)
{
   if (node == null || !node || !node.getID())
   {
      return;
   }

   var parentNode = node.getParent();
   var nl = [];
   while (parentNode != null && parentNode && parentNode.getID() && parentNode != rootNode)
   {
      nl.push(parentNode);
      parentNode = parentNode.getParent();
   }
   for (var i = nl.length - 1; i >= 0; i--)
   {
      var n = nl[i];
      if (!n.isShown())
      {
        handleNode(n.getID());
      }
      else
      {
         var submenu = document.getElementById('node' + n.getID() + 'sub');
         if (submenu && submenu.style.display == 'none')
         {
            handleNode(n.getID());
         }
      }
   }
   selectNode(node.getID());
}

function readStates() {
   if (!useCookieState) {
      return;
   }
   //setCookie('tree' + documentID,'');
   states = getCookie('tree' + documentID);
   if (states != null) {
      var array = states.split(';');
      for(var i=0;i<array.length;i++) {
         var singlestate = array[i].split('|');
         statearray[i] = new Array();
         statearray[i]["key"] = singlestate[0];
         statearray[i]["state"]  = singlestate[1];
      }
   }
}
function getState(nodeID) {
   for(var i=0;i<statearray.length;i++) {
      if (statearray[i]["key"] == nodeID) {
         state = statearray[i]["state"];
         if (state == null || state == '') {
            state = 'closed';
         }
         return state;
      }
   }
   return "closed";
}
function writeStates(nodeID,newstate) {
   if (!useCookieState) {
      return;
   }

   //alert(nodeID);
   var str = '';
   var found = false;
   for(var i=0;i<statearray.length;i++) {
      if (statearray[i]["key"] == nodeID) {
         statearray[i]["state"] = newstate;
         found = true;
      }
      if (statearray[i]["state"] != null) {
         str += statearray[i]["key"] + '|' + statearray[i]["state"] + ';';
      }
   }
   if (found == false) {
      statearray[statearray.length] = new Array();
      statearray[statearray.length - 1]["key"] = nodeID;
      statearray[statearray.length - 1]["state"] = newstate;
      if (newstate != null) {
         str += nodeID + '|' + newstate + ';';
      }
   }
   setCookie('tree' + documentID,str);
}
function showTree(path) {
   readStates();

   href = path;
   window.focus();
   window.onblur = blurSelection;
   window.onfocus = focusSelection;
   rootNode.setShown(true);
   var str = '';
   str = '<div id="node' + rootNode.getID() + '" class="treetitle" style="display:' + (showRootNode == true ? 'block' : 'none') + '">';
   str += '<nobr>';
   if (rootNode.hasIcon()) {
      str += '<img src="' + rootNode.getIcon() + '" style="vertical-align:middle;">';
   }
   str += '<span style="vertical-align:middle;">&nbsp;' + rootNode.getName() + '</span>';
   str += '</nobr></div>';

   if (rootNode.hasChilds()) {
      for(i=0;i<rootNode.childs.length;i++) {
         rootNode.childs[i].setShown(true);
         nodeContents = showNode(rootNode.childs[i],(i == (rootNode.getChildCount() -1)));
         str = str + nodeContents;
      }
   }
   container.innerHTML = str;
   if (window.finishedLoading) {
      finishedLoading();
   }
}
/**
* Shows the given node, and subnodes.
*/
function showNode(treeNode,lastNode) {
   linestring = treeNode.getLineString();
   var state = getState(treeNode.getID());
   var str;
   str = '<div id="node' + treeNode.getID() + '">';
   str += '<nobr>';
   for(var y=0;y<linestring.length;y++) {
      if (linestring.charAt(y) == 'I') {
         str += '<img src="' + href + iconPath + '/' + (showLines ? 'line' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';
      }
      else if (linestring.charAt(y) == 'B') {
         str += '<img src="' + href + iconPath + '/white.gif" style="width:19px;height:20px;vertical-align:middle;">';
      }
   }
   if (treeNode.hasChilds()) {
      // If this is the first child of the rootNode, and showRootNode is false, we want to display a different icon.
      if (!showRootNode && (treeNode.getParent() == rootNode) && (treeNode.getParent().getFirstChild() == treeNode)) {
         if (!lastNode) {
            str += '<img id="handler' + treeNode.getID() + '" src="' + href + iconPath + '/' + (state == 'open' ? (showLines ? 'minus_no_root' : 'minus_nolines') : (showLines ? 'plus_no_root' : 'plus_nolines')) + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';
         }
         else {
            str += '<img id="handler' + treeNode.getID() + '" src="' + href + iconPath + '/' + (state == 'open' ? 'minus_last' : 'plus_last') + '_no_root.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';
         }
      }
      else {
         if (!lastNode) {
            str += '<img id="handler' + treeNode.getID() + '" src="' + href + iconPath + '/' + (state == 'open' ? (showLines ? 'minus' : 'minus_nolines') : (showLines ? 'plus' : 'plus_nolines')) + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';
         }
         else {
            str += '<img id="handler' + treeNode.getID() + '" src="' + href + iconPath + '/' + (state == 'open' ? (showLines ? 'minus_last' : 'minus_nolines') : (showLines ? 'plus_last' : 'plus_nolines')) + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';
         }
      }
   }
   else {
      // If this is the first child of the rootNode, and showRootNode is false, we want to display a different icon.
      if (!showRootNode && (treeNode.getParent() == rootNode) && (treeNode.getParent().getFirstChild() == treeNode)) {
         if (!lastNode) {
            str += '<img id="handler' + treeNode.getID() + '" src="' + href + iconPath + '/' + (showLines ? 't_no_root' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';
         }
         else {
            str += '<img id="handler' + treeNode.getID() + '" src="' + href + iconPath + '/white.gif" style="width:19px;height:20px;vertical-align:middle;">';
         }
      }
      else {
         if (!lastNode) {
            str += '<img id="handler' + treeNode.getID() + '" src="' + href + iconPath + '/' + (showLines ? 't' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';
         }
         else {
            str += '<img id="handler' + treeNode.getID() + '" src="' + href + iconPath + '/' + (showLines ? 'lastnode' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';
         }
      }
   }
   iconStartImage = treeNode.getIcon();
   if (state != 'closed') {
      if (treeNode.hasChilds()) {
         iconStartImage = treeNode.getOpenIcon();
      }
   }
   if (treeNode.hasIcon()) {
      str += '<img id="iconimage' + treeNode.getID() + '" src="' + iconStartImage + '" style="vertical-align:middle;" OnClick="selectNode(' + treeNode.getID() + ')">&nbsp;';
   }
   else {
      str += '<img id="iconimage' + treeNode.getID() + '"  width="0" height="0" src="' + iconStartImage + '" style="vertical-align:middle;" OnClick="selectNode(' + treeNode.getID() + ')">';
   }

   str += '<span unselectable="ON" style="vertical-align:middle;" class="treetitle" ID="title' + treeNode.getID() + '" OnDblClick="handleNode(' + treeNode.getID() + ')" OnClick="selectNode(' + treeNode.getID() + ')">';
   str += treeNode.getName();
   str += '</span>';
   str += '</nobr>';
   str += '</div>';

   if (treeNode.hasChilds() && treeNode.isShown()) {
      if (state == 'open') {
         str += '<div id="node' + treeNode.getID() + 'sub" style="display:block;">';
         fireOpenEvent(treeNode);
         // alert('openevent: ' + treeNode.getName());
      }
      else {
         str += '<div id="node' + treeNode.getID() + 'sub" style="display:' + (showAllNodesOnStartup == true ? 'block;' : 'none;') + ';">';
      }
      var subgroupstr = '';
      var newChar = '';

      if (!lastNode) {
         newChar = 'I';
      }
      else {
         newChar = 'B';
      }
      for(var z=0;z<treeNode.getChildCount();z++) {
         treeNode.childs[z].setLineString(linestring + newChar);
      }
      for(var z=0;z<treeNode.getChildCount();z++) {
         subgroupstr += showNode(treeNode.childs[z],(z == (treeNode.getChildCount() -1)));
      }
      str += subgroupstr;
      str += '</div>';
   }
   else {
      str += '<div id="node' + treeNode.getID() + 'sub" style="display:none;">';
      str += '</div>';
   }

   return str;
}
/*
function mouseMove() {
   if (dragging) {
      alert('bob');
   }
}
function mouseUp() {
   if (dragging) {
      alert('dropped on something!');
   }
}
*/
function startDrag(nodeID) {
   if (!dragable) {
      return;
   }
   draggedNodeID = nodeID;

   var srcObj = window.event.srcElement;
   while(srcObj.tagName != 'DIV') {
      srcObj = srcObj.parentElement;
   }
   floatDragElement = document.createElement('DIV');

   floatDragElement.innerHTML = srcObj.innerHTML;
   floatDragElement.childNodes[0].removeChild(floatDragElement.childNodes[0].childNodes[0]);

   document.body.appendChild(floatDragElement);
   floatDragElement.style.zIndex = 100;
   floatDragElement.style.position = 'absolute';
   floatDragElement.style.filter='progid:DXImageTransform.Microsoft.Alpha(1,opacity=60);';
}

function findSpanChild(element) {
   if (element.tagName == 'SPAN') {
      return element;
   }
   else {
      if (element.childNodes) {
         for(var i=0;i<element.childNodes.length;i++) {
            var value = findSpanChild(element.childNodes[i]);
            if (value != false) {
               return value;
            }
         }
         return false;
      }
   }
}
function dragEnter(nodeID) {
   if (!dragable) {
      return;
   }
   lastDraggedOnNodeID = nodeID;

   if (colouredElement) {
      findSpanChild(colouredElement).className = 'treetitle';
   }
   colouredElement = window.event.srcElement;
   while(colouredElement.tagName != 'DIV') {
      colouredElement = colouredElement.parentElement;
      if (colouredElement.tagName == 'BODY') {
         // Something gone seriously wrong.
         alert('Drag failure, reached <BODY>!');
         return;
      }
   }
   findSpanChild(colouredElement).className = 'treetitleselectedfocused';
}
function dragLeave() {
   if (!dragable) {
      return;
   }
}
function endDrag(nodeID) {
   if (!dragable) {
      return;
   }
   if (lastDraggedOnNodeID != null) {
      fireMoveEvent(getTreeNode(lastDraggedOnNodeID),draggedNodeID,lastDraggedOnNodeID);
   }
}
function dragProceed() {
   if (!dragable) {
      return;
   }
   var dragged = getTreeNode(draggedNodeID);
   var newparent = getTreeNode(lastDraggedOnNodeID);

   var oldparent = dragged.getParent();

   oldparent.removeChild(dragged);
   newparent.addChild(dragged);

   refreshNode(oldparent);
   refreshNode(newparent);

   _dragClean()
}
function dragCancel() {
   if (!dragable) {
      return;
   }
   _dragClean()
}
/**
* Don't call this yourself.
*/
function _dragClean() {
   if (!dragable) {
      return;
   }
   if (colouredElement) {
      findSpanChild(colouredElement).className = 'treetitle';
   }

   floatDragElement.parentElement.removeChild(floatDragElement);
   floatDragElement = null;
   colouredElement = null;
   draggedNodeID = null;
   lastDraggedOnNodeID = null;
}
function dragMove() {
   if (!dragable) {
      return;
   }
   floatDragElement.style.top = window.event.clientY;
   floatDragElement.style.left = window.event.clientX;
}
function editEnded() {
   if (treeNodeEdited != null) {
      // treeNodeEdited.getID();
      var editTitle = document.getElementById('title' + treeNodeEdited.getID());
      var input = editTitle.childNodes[0];

      var newValue = input.value;

      if (newValue == treeNodeEdited.getName()) {
         editTitle.innerHTML = newValue;
         treeNodeEdited = null;
         return;
      }

      fireEditEvent(treeNodeEdited,newValue);

      if (!editaborted) {
         treeNodeEdited.setName(newValue);
         editTitle.innerHTML = newValue;
      }

      treeNodeEdited = null;
   }
}


function selectNode(nodeID) {
   var treeNode = getTreeNode(nodeID);
   if (!treeNode)
   {
      return;
   }
   if (selectedNode != null) {
      if (selectedNode == nodeID) {
         if (treeNode.isEditable()) {
            if (treeNodeEdited == treeNode) {
               return;
            }
            treeNodeEdited = treeNode;
            var editTitle = document.getElementById('title' + treeNode.getID());
            editTitle.className = 'editednode';


            editTitle.innerHTML = '<input type="text" onKeypress="if (event.keyCode == 13) { this.onblur = null; editEnded(); }" name="editednode" class="editednodeinput">';
            var input = editTitle.childNodes[0];
            input.value = treeNode.getName();
            input.focus();
            input.select();
            input.onblur = editEnded;
         }
         return;
      }
      if (treeNodeEdited != null) {
         editEnded();
      }
      var oldNodeTitle = document.getElementById('title' + selectedNode);
      oldNodeTitle.className = 'treetitle';
   }
   selectedNode = nodeID;
   var nodetitle = document.getElementById('title' + selectedNode);
   nodetitle.className = 'treetitleselectedfocused';
   logNode(treeNode);
   if (treeNode.gotHandler()) {
      eval(treeNode.getHandler() + '(getTreeNode(' + nodeID + '));');
   }
   else {
      standardClick(treeNode);
   }
}
function refreshNode(treeNode) {
   var submenu = document.getElementById('node' + treeNode.getID() + 'sub');
   var str = '';
   for(var i=0;i<treeNode.getChildCount();i++) {
      var parent = treeNode.getParent();
      if (!parent) {
         treeNode.childs[i].setLineString(treeNode.getLineString() + 'B');
      }
      else {
         if (parent.childs[parent.childs.length - 1] == treeNode) {
            treeNode.childs[i].setLineString(treeNode.getLineString() + 'B');
         }
         else {
            treeNode.childs[i].setLineString(treeNode.getLineString() + 'I');
         }
      }
      treeNode.childs[i].setShown(true);
      str += showNode(treeNode.childs[i],i == (treeNode.getChildCount() - 1));
   }
   var actionimage = document.getElementById('handler' + treeNode.getID());
   if (treeNode.getChildCount() == 0) {
      // TreeNode haven't got any children, make sure the right image is displayed.
      if (actionimage.src.indexOf('last') == -1) {
         actionimage.src = href + iconPath + '/' + (showLines ? 't' : 'white') + '.gif';
      }
      else {
         actionimage.src = href + iconPath + '/' + (showLines ? 'lastnode' : 'white') + '.gif';
      }
      actionimage.onclick = null;

      // Close the submenu
      if (submenu) {
         submenu.style.display = 'none';
      }
   }
   else {
      // We have children, make sure to display the + and - icon.
      if (actionimage.src.indexOf('plus') != -1) {
         // The TreeNode have already got children, and displays them.
      }
      else if (actionimage.src.indexOf('minus') != -1) {
         // The TreeNode have already got children, and displays them.
      }
      else {
         if (actionimage.src.indexOf('last') == -1) {
            actionimage.outerHTML = '<img id="handler' + treeNode.getID() + '" src="' + href + iconPath + '/' + (showLines ? 'plus' : 'plus_nolines') + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';
         }
         else {
            actionimage.outerHTML = '<img id="handler' + treeNode.getID() + '" src="' + href + iconPath + '/plus_last.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';
         }
      }
   }
   submenu.innerHTML = str;
}

function isNodeExpanded(nodeID)
{
   // Added by AEI
   var rval = false;
   var submenu = document.getElementById('node' + nodeID + 'sub');
   if (submenu && submenu.style.display == 'block') {
      rval = true;
   }
   return rval;
}

function handleNode(nodeID) {
   var treeNode = getTreeNode(nodeID);
   if (supportDoubleClick && treeNode && !treeNode.hasChilds())
   {
      // AEI - handle double click on a leaf
      doubleClick(treeNode);
      return;
   }

   if (!treeNode || !treeNode.hasChilds()) { // No reason to handle a node without childs.
      return;
   }
   var submenu = document.getElementById('node' + nodeID + 'sub');
   //logNode(treeNode);
   // Added by AEI - build html if needed (lazy build) based on the 'shown' flag.
   if (!treeNode.isShown())
   {
      treeNode.setShown(true);
      var lastNode = false;
      var parent = treeNode.getParent();
      if (parent && parent.childs[parent.childs.length - 1] == treeNode)
      {
         lastNode = true;
      }
      var linestring = treeNode.getLineString();
      var nodeContents = "";
      var newChar = lastNode? 'B' : 'I';
      for(var z=0;z<treeNode.getChildCount();z++) {
         treeNode.childs[z].setLineString(linestring + newChar);
      }
      for(i=0;i<treeNode.childs.length;i++) {
         //treeNode.childs[i].setShown(true);
         nodeContents += showNode( treeNode.childs[i], (i == (treeNode.getChildCount() -1)) );

      } // for
     submenu.innerHTML = nodeContents;
   }


   var iconimageholder = document.getElementById('iconimage' + nodeID);
   var actionimage = document.getElementById('handler' + nodeID);

   // This will be used if showRootNode is set to false.
   var firstChildOfRoot = false;
   if (actionimage.src.indexOf('_no_root') != -1) {
      firstChildOfRoot = true;
   }

   if (submenu.style.display == 'none') {
      writeStates(nodeID,'open');
      fireOpenEvent(treeNode);
      submenu.style.display = 'block';

      iconimageholder.src = treeNode.getOpenIcon();

      if (actionimage.src.indexOf('last') == -1) {
         actionimage.src = href + iconPath + '/' + ((firstChildOfRoot) ? 'minus_no_root' : (showLines ? 'minus' : 'minus_nolines')) + '.gif';
      }
      else {
         actionimage.src = href + iconPath + '/' + ((firstChildOfRoot) ? 'minus_last_no_root' : (showLines ? 'minus_last' : 'minus_nolines')) + '.gif';
      }
   }
   else {
      writeStates(nodeID,'closed');
      submenu.style.display = 'none';

      iconimageholder.src = treeNode.getIcon();

      if (actionimage.src.indexOf('last') == -1) {
         actionimage.src = href + iconPath + '/' + ((firstChildOfRoot) ? 'plus_no_root' : (showLines ? 'plus' : 'plus_nolines')) + '.gif';
      }
      else {
         actionimage.src = href + iconPath + '/' + ((firstChildOfRoot) ? 'plus_last_no_root' : (showLines ? 'plus_last' : 'plus_nolines')) + '.gif';
      }
   }
}
function fireOpenEvent(treeNode) {
   if (treeNode.gotOpenEventListeners()) {
      for(var i=0;i<treeNode.openeventlisteners.length;i++) {
         eval(treeNode.openeventlisteners[i] + '(' + treeNode.getID() + ');');
      }
   }
}
function fireEditEvent(treeNode,newVal) {
   if (treeNode.gotEditEventListeners()) {
      for(var i=0;i<treeNode.editeventlisteners.length;i++) {
         eval(treeNode.editeventlisteners[i] + '(' + treeNode.getID() + ',\'' + escape(newVal) + '\');');
      }
   }
}
function fireMoveEvent(treeNode,draggedNodeID,droppedOnNodeID) {
   if (treeNode.gotMoveEventListeners()) {
      for(var i=0;i<treeNode.moveeventlisteners.length;i++) {
         eval(treeNode.moveeventlisteners[i] + '(' + draggedNodeID + ',' + droppedOnNodeID + ');');
      }
   }
}
function blurSelection() {
   if (selectedNode != null) {
      var oldNodeTitle = document.getElementById('title' + selectedNode);
      oldNodeTitle.className = 'treetitleselectedblured';
   }
}
function focusSelection() {
   if (selectedNode != null) {
      var oldNodeTitle = document.getElementById('title' + selectedNode);
      oldNodeTitle.className = 'treetitleselectedfocused';
   }
}
function getCookieVal (offset) {
   var endstr = document.cookie.indexOf (";",offset);
   if (endstr == -1) {
      endstr = document.cookie.length;
   }
   return unescape(document.cookie.substring(offset,endstr));
}
function getCookie (name) {
   var arg = name + "=";
   var alen = arg.length;
   var clen = document.cookie.length;
   var i = 0;
   while (i < clen) {
      var j = i + alen;
      if (document.cookie.substring(i, j) == arg) {
         return getCookieVal(j);
      }
      i = document.cookie.indexOf(" ", i) + 1;
      if (i == 0) {
         break;
      }
   }
   return null;
}
function setCookie (name, value) {
   var argv = setCookie.arguments;
   var argc = setCookie.arguments.length;
   var expires = (argc > 2) ? argv[2] : null;
   var path = (argc > 3) ? argv[3] : null;
   var domain = (argc > 4) ? argv[4] : null;
   var secure = (argc > 5) ? argv[5] : false;
   document.cookie = name + "=" + escape (value) + ((expires == null) ? "" : ("; expires=" + expires.toGMTString())) + ((path == null) ? "" : ("; path=" + path)) + ((domain == null) ? "" : ("; domain=" + domain)) + ((secure == true) ? "; secure" : "");
}
function expandNode() {
   var state = getState(selectedNode);
   if (state == 'open') {
      var currentTreeNode = getTreeNode(selectedNode);
      if (currentTreeNode.hasChilds()) {
         selectNode(currentTreeNode.childs[0].getID());
      }
   }
   else {
      handleNode(selectedNode);
   }
}
function subtractNode() {
   var state = getState(selectedNode);
   if (state == 'closed') {
      var currentTreeNode = getTreeNode(selectedNode);
      var parent = currentTreeNode.getParent();
      if (parent != null && parent != rootNode) {
         selectNode(parent.getID());
      }
   }
   else {
      handleNode(selectedNode);
   }
}
function selectPrevNode() {
   var currentTreeNode = getTreeNode(selectedNode);
   if (currentTreeNode.prevSibling != null) {

      var state = getState(currentTreeNode.prevSibling.getID());

      if (state == 'open' && currentTreeNode.prevSibling.hasChilds()) {
         // We have to find the last open child of the previoussiblings childs.
         var current = currentTreeNode.prevSibling.childs[currentTreeNode.prevSibling.childs.length - 1];
         var currentstate = 'open';
         while (current.hasChilds() && (getState(current.getID()) == 'open')) {
            current = current.childs[current.childs.length - 1];
         }
         selectNode(current.getID());
      }
      else {
         selectNode(currentTreeNode.prevSibling.getID());
      }
   }
   else {
      if (currentTreeNode.getParent() != null && currentTreeNode.getParent() != rootNode) {
         selectNode(currentTreeNode.getParent().getID());
      }
   }
}
function selectNextNode() {
   var currentTreeNode = getTreeNode(selectedNode);

   var state = getState(selectedNode);
   if (state == 'open' && currentTreeNode.hasChilds()) {
      selectNode(currentTreeNode.childs[0].getID());
   }
   else {
      if (currentTreeNode.nextSibling != null) {
         selectNode(currentTreeNode.nextSibling.getID());
      }
      else {
         // Continue up the tree until we either hit null, or a parent which have a child.
         var parent = currentTreeNode;
         while ((parent = parent.getParent()) != rootNode) {
            if (parent.nextSibling != null) {
               selectNode(parent.nextSibling.getID());
               break;
            }
         }
         /*
         if (currentTreeNode.getParent().nextSibling != null) {
            selectNode(currentTreeNode.getParent().nextSibling.getID());
         }
         */
      }
   }
}

function handleUp()
{
   // Added by AEI
   // walk up. if at the top then choose parent.
   var nextNode = null;
   var currNode = getTreeNode(selectedNode);
   if (currNode == null)
   {
      return;
   }
   if (currNode.prevSibling != null) {
      nextNode = currNode.prevSibling;
   }
   else if (currNode.getParent() != null)
   {
      nextNode = currNode.getParent()
   }
   if (nextNode != null && nextNode != rootNode)
   {
      selectNode(nextNode.getID());
   }
}

function handleDown()
{
   // Added by AEI
   // walk down. if at last node, then go to parent's next sibling.
   var nextNode = null;
   var currNode = getTreeNode(selectedNode);
   if (currNode == null)
   {
      return;
   }
   var expanded = isNodeExpanded(currNode.getID());
   if (currNode.hasChilds() && expanded && currNode.childs[0] != null)
   {
      // if node and it expanded, then select first child.
      nextNode = currNode.childs[0];
   }
   else if (currNode.nextSibling != null) {
      // if there is a next sibling, then select it.
      nextNode = currNode.nextSibling;
   }
   else
   {
      // at the last leaf, so choose the next available sibling of the parent.
      currNode = currNode.getParent();
      while(currNode != null && currNode.nextSibling == null)
      {
         currNode = currNode.getParent();
      }
      if (currNode != null)
      {
         nextNode = currNode.nextSibling;
      }

   }
   if (nextNode != null && nextNode != rootNode)
   {
      selectNode(nextNode.getID());
   }
}

function handleLeft()
{
   // Added by AEI
   // if on a leaf, the go to parent
   // if on a expanded parent, then collapse parent
   // if on a collapsed parent, then go up one level to its parent.
   var nextNode = null;
   var currNode = getTreeNode(selectedNode);
   if (currNode == null)
   {
      return;
   }
   var expanded = isNodeExpanded(currNode.getID());
   if (!currNode.hasChilds() && currNode.getParent() != null)
   {
      // on a leaf - jump to the parent..
      nextNode = currNode.getParent();
   }
   else if (currNode.hasChilds() && !expanded && currNode.getParent() != null)
   {
      // on a parent which is already collapsed - move up one..
      nextNode = currNode.getParent();
   }
   else if (currNode.hasChilds() && expanded)
   {
      // on a parent which is already expanded - so, simple collapse it and return.
      handleNode(selectedNode);
   }

   if (nextNode != null && nextNode != rootNode)
   {
      selectNode(nextNode.getID());
   }

}

function handleRight()
{
   // Added by AEI
   // if parent, then expand, else nada!
   var nextNode = null;
   var currNode = getTreeNode(selectedNode);
   if (currNode == null)
   {
      return;
   }
   if ( currNode.hasChilds() && !isNodeExpanded( currNode.getID() ) )
   {
      expandNode();
   }
}

function handleEnterKey()
{
   // Added by AEI
   // simulate 'double click' for enter key.
   var nextNode = null;
   var currNode = getTreeNode(selectedNode);
   if (currNode != null && supportDoubleClick)
   {
      handleNode(currNode.getID());
   }
}

function keyDown(event) {
   if (!supportKeyboardNavigation)
   {
   	return true;
   }
   var currentTreeNode = getTreeNode(selectedNode);
   if (window.event) {
      event = window.event;
   }
   if (event.keyCode == 38) { // Up
      handleUp();
      return false;
   }
   else if (event.keyCode == 40) { // Down
      handleDown();
      return false;
   }
   else if (event.keyCode == 37) { // left
      handleLeft();
      return false;
   }
   else if (event.keyCode == 39) { // right
      handleRight();
      return false;
   }
   else if (event.keyCode == 13) { // enter key (double click)
	   handleEnterKey();
	   return false;
   }
}
document.onkeydown = keyDown;